package tracker

import (
	"commonAcquire"
	"fmt"
	"net"
	"rpcclient"
	"strconv"
	"strings"
)

type Tracker struct {
	hostAndPort string
	listener    *net.TCPListener
	maxRead     int
	Infos       commonAcquire.AircraftInfo
}

func NewTracker() *Tracker {
	return &Tracker{}
}

func (p *Tracker) Init() {
	p.maxRead = 10000
	p.hostAndPort = "127.0.0.1:54321"
	p.listener = p.initServer(p.hostAndPort)
}

func (p *Tracker) initServer(hostAndPort string) *net.TCPListener {
	serverAddr, err := net.ResolveTCPAddr("tcp", hostAndPort)
	p.checkError(err, "Resolving address:port failed: '"+hostAndPort+"'")
	listener, err := net.ListenTCP("tcp", serverAddr)
	p.checkError(err, "ListenTCP: ")
	println("Listening to: ", listener.Addr().String())
	return listener
}

func (p *Tracker) StartTrack() {
	for {
		conn, err := p.listener.AcceptTCP()
		conn.SetKeepAlive(true)
		p.checkError(err, "Accept: ")
		if err != nil {
			continue
		}
		go p.connectionHandler(conn)
	}
}

func (p *Tracker) StopTrack() {

}

func (p *Tracker) connectionHandler(conn net.Conn) {
	connFrom := conn.RemoteAddr().String()
	println("Connection from: ", connFrom)
	for {
		var ibuf []byte = make([]byte, p.maxRead+1)
		length, err := conn.Read(ibuf[0:p.maxRead])
		ibuf[p.maxRead] = 0 // to prevent overflow
		switch err {
		case nil:
			p.handleMsg(length, err, ibuf)

		default:
			goto DISCONNECT
		}
	}
DISCONNECT:
	err := conn.Close()
	println("Closed connection:", connFrom)
	p.checkError(err, "Close:")
}

func (p *Tracker) handleMsg(length int, err error, msg []byte) {
	if length > 0 {

		for i := 0; ; i++ {
			if msg[i] == 0 {
				break
			}
		}
		originMsg := string(msg[0:length])
		fmt.Printf("Received data: %v", originMsg)
		fmt.Println("   length:", length)
		p.parseMsg(originMsg)
	}

}

func (p *Tracker) parseMsg(msg string) {
	if strings.Contains(msg, "*HQ") && strings.Contains(msg, "#") {
		array := strings.Split(msg, ",")
		longitudeTmp, _ := strconv.ParseFloat(array[7], 2)
		latitudeTmp, _ := strconv.ParseFloat(array[5], 2)
		altitudeTmp, _ := strconv.ParseFloat(array[11], 2)
		speedTmp, _ := strconv.ParseFloat(array[9], 2)
		directionTmp, _ := strconv.ParseFloat(array[10], 2)
		p.Infos = commonAcquire.AircraftInfo{array[1], longitudeTmp, latitudeTmp,
			altitudeTmp, speedTmp, directionTmp}

		rpcclient.PushStore(p.Infos)
		rpcclient.PushService(p.Infos)
	}
	fmt.Println(p.Infos)
}

func (p *Tracker) checkError(error error, info string) {
	if error != nil {
		panic("ERROR: " + info + " " + error.Error()) // terminate program
	}
}
